package max.ta.data.plot;

import java.awt.Color;
import java.awt.Dimension;
import java.util.List;

import max.ta.data.plot.data.MathLine;
import max.ta.data.plot.data.MathPoint;
import max.ta.data.plot.data.MathSurface;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.RefineryUtilities;

public abstract class AbstractChartPlotter<X extends Comparable<X>, Y>
	extends ApplicationFrame
	implements ChartPlotter<X, Y> {

    private static final long serialVersionUID = 1L;
    // ----------------------------------------------------------------------------------------
    // Dimension
    // ----------------------------------------------------------------------------------------
    private static final int HEIGHT = 540;
    private static final int WIDTH = 1000;
    private static final Dimension DIMENSION = new Dimension(WIDTH, HEIGHT);
    // ----------------------------------------------------------------------------------------
    // Inset
    // ----------------------------------------------------------------------------------------
    private static final double INSET = 2.0;
    private static final RectangleInsets OFFSET_RECTANGLE = new RectangleInsets(INSET, INSET, INSET, INSET);
    // ----------------------------------------------------------------------------------------
    // Visible
    // ----------------------------------------------------------------------------------------
    protected static final boolean VISIBLE = true;
    protected static final boolean LEGEND = true;
    protected static final boolean TOOLTIPS = true;
    protected static final boolean URL = false;
    private static final boolean BASE_SHAPE_VISIBLE = true;
    private static final boolean SERIE_LINE_VISIBLE = true;
    // ----------------------------------------------------------------------------------------
    // Labels
    // ----------------------------------------------------------------------------------------
    protected static final String Y_LABEL = "Value";
    protected static final String X_LABEL = "Category";
    // ----------------------------------------------------------------------------------------
    // title
    // ----------------------------------------------------------------------------------------
    protected final String title;
    private final ValueAxis xAxis;
    private final ValueAxis yAxis;

    public AbstractChartPlotter(final String title, ValueAxis xAxis, ValueAxis yAxis) {
	super(title);
	this.title = title;
	this.xAxis = xAxis;
	this.yAxis = yAxis;
    }

    @Override
    public String getTitle() {
	return title;
    }

    @Override
    public void plot(String serieName, List<MathPoint<X, Y>> points) {
	final MathLine<X, Y> line = new MathLine<X, Y>(serieName);
	line.addAll(points);
	MathSurface<X, Y> pointsSets = new MathSurface<X, Y>();
	pointsSets.add(line);
	plot(pointsSets);
    }

    @Override
    public void plot(MathSurface<X, Y> pointsSets) {
	final JFreeChart chart = createChart(pointsSets);
	final ChartPanel chartPanel = createChartPanel(chart);
	// Frame
	setContentPane(chartPanel);
	pack();
	RefineryUtilities.centerFrameOnScreen(this);
	setVisible(VISIBLE);
    }

    protected ChartPanel createChartPanel(final JFreeChart chart) {
	final XYPlot plot = chart.getXYPlot();
	final XYItemRenderer renderer = plot.getRenderer();
	final ChartPanel chartPanel = new ChartPanel(chart);
	// Chart
	chart.setBackgroundPaint(Color.white);
	// plot
	plot.setDomainAxis(xAxis);
	plot.setRangeAxis(yAxis);
	plot.setOutlinePaint(Color.black);
	plot.setBackgroundPaint(Color.lightGray);
	plot.setDomainGridlinePaint(Color.white);
	plot.setRangeGridlinePaint(Color.white);
	plot.setAxisOffset(OFFSET_RECTANGLE);
	plot.setDomainCrosshairVisible(VISIBLE);
	plot.setRangeCrosshairVisible(VISIBLE);
	if (renderer instanceof XYLineAndShapeRenderer) {
	    XYLineAndShapeRenderer r = (XYLineAndShapeRenderer) renderer;
	    r.setBaseShapesVisible(BASE_SHAPE_VISIBLE);
	    r.setBaseShapesFilled(BASE_SHAPE_VISIBLE);
	    r.setDrawSeriesLineAsPath(SERIE_LINE_VISIBLE);
	}
	// Chart Panel
	chartPanel.setPreferredSize(DIMENSION);
	chartPanel.setFillZoomRectangle(VISIBLE);
	chartPanel.setMouseWheelEnabled(VISIBLE);
	return chartPanel;
    }

    public static class LocalChartFactory {
	// FACTORIES
    }

    protected abstract JFreeChart createChart(MathSurface<X, Y> points);
}
